package upnp

import (
	"encoding/xml"
	"fmt"
	"net/http"
	"strings"
)

// GetExtIPAction get external ip address
type GetExtIPAction struct {
	actionData
}

func newGetExtIPAction(srv *Service, in, out []string) *GetExtIPAction {
	return &GetExtIPAction{
		actionData{
			name:  "GetExternalIPAddress",
			srv:   srv,
			args:  in,
			resps: out,
		},
	}
}

type getExtIPBody struct {
	ActionBodyContent
}

func (a *GetExtIPAction) requestBody(i int) (*actionBodyType, error) {
	body := new(getExtIPBody)
	body.Init(a.actionData)
	return newActionBody(body)
}

type getExtIPResponse struct {
	Addr   string `xml:"Body>GetExternalIPAddressResponse>NewExternalIPAddress"`
	Code   string `xml:"Body>Fault>faultcode"`
	String string `xml:"Body>Fault>faultstring"`
	Detail struct {
		UPnPError struct {
			Code        int    `xml:"errorCode"`
			Description string `xml:"errorDescription"`
		} `xml:"UPnPError"`
	} `xml:"Body>Fault>detail"`
}

// Do get external ip address, ip address in ActionResponse.Data in string type
func (a *GetExtIPAction) Do(i int) (*ActionResponse, error) {
	obj, err := a.requestBody(i)
	if err != nil {
		return nil, err
	}
	bodyData, err := xml.Marshal(obj)
	if err != nil {
		return nil, err
	}
	data := xml.Header + string(bodyData)
	resp, err := a.sendRequest(strings.NewReader(data), len(data))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var ret getExtIPResponse
	if err := xml.NewDecoder(resp.Body).Decode(&ret); err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("AddPortMapping failed: %d/%s",
			ret.Detail.UPnPError.Code, ret.Detail.UPnPError.Description)
	}
	return &ActionResponse{
		Code: 0,
		Data: ret.Addr,
	}, nil
}
